var c, ctx, canvas;

$(document).ready(function(){
    c       = document.getElementById("myCanvas");
    ctx     = c.getContext("2d");
    canvas  = {
        width : $("#myCanvas").width(),
        height: $("#myCanvas").height(),
        pixel : 10
    };
    
    $("#command").focus().bind("blur", function(){
        $(this).focus();
    });
});

function log( type, msg )
{
    if(type==1)
        $("#log").addClass("success").removeClass("error warning");
    else if(type==0)
        $("#log").removeClass("success warning").addClass("error")
    else 
        $("#log").removeClass("success error").addClass("warning");

    $("#msg").html(msg);
}

$("#command").on("keyup", function(e){
    
    var code = e.keyCode ? e.keyCode : e.which;
    if( code == 13){//Enter Key Pressed
        if( command_buffer.length > 10 )
            command_buffer = com_old.slice(1);
        command_buffer.push($("#command").val());
        currCommand = "";
        comCounter = command_buffer.length;
        $("#exec").click();
    }
    else if( code == 38){//Up Arrow Key Press
        if( $("#command").val().length > 0 )
            currCommand = $("#command").val();
        
        comCounter = comCounter > 0 ? --comCounter : 0;
        if( command_buffer.length > 0 ){
            $("#command").val(command_buffer[comCounter]);
        }   
    }
    else if( code == 40){//Down Arrow Key Pressed
        
        if( command_buffer.length > 0 && comCounter <= command_buffer.length-2)
        {
            $("#command").val(command_buffer[++comCounter]);
        }
        else if( comCounter == command_buffer.length - 1)
        {
            $("#command").val(currCommand);
        }
    }

    var com = $(this).val();
    var comList = com.split(" ");
    parseCommand(comList);
});

$("#exec").on("click", function(){
    
    var command = $("#command").val();
    var comList = command.split(" ");
    var func = comList[0];
    try{
        algo[func].run(comList.slice(1));
    }
    catch(err)
    {
        log(0, err);
    }
    finally
    {
        $("#command").val("");
    }
});

function parseCommand( command )
{
    searchCom( command[0] );
}

function searchCom( item )
{
    if( item.length == 0 )
    {
        $("#syn > .content").html( "Just type in Commands like<br /><code>pixel 2 3 30 40</code><br />To Draw a Pixel" );
        $("#doc > .content").html( "This area displays docstring attached to command" );
    }
    else{
        //Currently using linear searchCom
        //will implement Binary search if the function size exceeds
        for( var i = 0; i < commands.length; i++)
        {
            if( item == commands[i].substr(0, item.length ) )
            {
                updateDocs( commands[i] );
                break;
            }
        }
    }
}

function updateDocs( command )
{
    $("#syn > .content").html( algo[command].syntax );
    $("#doc > .content").html( algo[command].doc);
}

var algo = {
    grid : {
        run : function(args)
        {
            if(args.length > 0) canvas.pixel = parseInt(args[0]);

            ctx.lineWidth = 0.3;
            ctx.strokeStyle = "grey";
            ctx.beginPath();

            log( 1, "Creating Grid with Following Parameters<br /><ul><li>Canvas Width : " + canvas.width + "</li><li>Canvas Height : " + canvas.height + "</li><li>Pixel : " + canvas.pixel + "</li></ul>" );
    
            for(var i = 0; i <= canvas.height; i+=canvas.pixel)
            {
                ctx.moveTo( 0, i );
                ctx.lineTo( canvas.width, i );
                ctx.stroke();
            }

            for(var i = 0; i <= canvas.width; i+=canvas.pixel)
            {
                ctx.moveTo( i, 0 );
                ctx.lineTo( i, canvas.height );
                ctx.stroke();
            }


            ctx.closePath()
            ctx.strokeStyle = "#000";
            ctx.lineWidth = 1;
            
        },
        syntax : "grid x",
        doc : "Creates Grid on Canvas<br />x : (int) spacing between line",
    },
    line : {
        run : function(args){
            
            if( args.length >= 4 )
            {
                var x1 = args[0],
                    y1 = args[1],
                    x2 = args[2],
                    y2 = args[3],
                    color = args.length >=5 ? args[4] : "#000";

                    ctx.beginPath();
                    ctx.strokeStyle = color;
                    ctx.moveTo(x1, y1);
                    ctx.lineTo(x2, y2);
                    ctx.stroke();
                    ctx.closePath();

            }
            else
            {
                log(0, "line requires 4 parameters only " + args.length + "provided");
            }
            
        },
        syntax : "line x1 y1 x2 y2 color",
        doc : "Draws a line from (x1, y1) to (x2, y2)<br />color : (Optional) in HEX",
    },
    pixel : {
        run : function(args)
        {
            var x = Math.round(args[0])*canvas.pixel,
            y = Math.round(args[1])*canvas.pixel;
            if( args.length > 2 && args[2] == 1)
            {
               log(1, "Created Pixel at (" + x + "," + y + ")"); 
            } 
            if( args.length > 3 )
            {
                try{
                    ctx.fillStyle = args[3];
                }
                catch(err)
                {
                    log(0, "Invalid Color provided, setting color to black");
                    ctx.fillStyle = "#000";
                }
            }
            ctx.fillRect( x,y, canvas.pixel, canvas.pixel );
        },
        syntax : "pixel (x) (y) (log) (color)",
        doc : "Draws a Pixel at (x,y)<br />x : x-Coordinate<br />y : y-Coordinate<br />log : (Optional)1 to Turn on Logging, 0 to Turnoff<br />color : (Optional)Hex Value of Color",
    },
    dda : {
        run : function( args )
        {

            console.log(args);

            if( args.length < 4 )
            {
                log(0, "Command Requires atleast 4 parameters only " + args.length + " provided");
                return;
            }

            var x1 = parseInt(args[0]),
                y1 = parseInt(args[1]),
                x2 = parseInt(args[2]),
                y2 = parseInt(args[3]);

            if( args.length > 4 )
            {
                try{
                    ctx.fillStyle = args[4];
                }
                catch(err)
                {
                    log(0, "Invalid Color provided, setting color to black");
                    ctx.fillStyle = "#000";
                }
            }
                

            var dx = x2 - x1,
            x = x1, y = y1,
			dy = y2 - y1,
			step = Math.abs(dx) > Math.abs(dy) ? Math.abs(dx) : Math.abs(dy),
			xIncr = dx / step,
			yIncr = dy / step;
			algo.pixel.run([x1, y1]);
            
            var counter = 1;
            var draw = setInterval( function(){
                x1 = x1 + xIncr;
				y1 = y1 + yIncr;
				algo.pixel.run([x1, y1]);
                counter++;
                if( counter >= step ) clearInterval( draw );
            }, 100 );

            log(1, "Created Line using DDA with following Parameters<br /><ul><li>From (" + x + ", " + y + ") to (" + x2 + ", " + y2 + ")</li><li>dx : " + dx + "</li><li>dy : " + dy + "</li><li>xIncr : " + xIncr + "</li><li>yIncr : " + yIncr + "</li><li>Step : " + step + "</li></ul>" );
            
            
        },
        syntax : "dda (x1) (y1) (x2) (y2) (color)",
        doc : "DDA Algorithm for Drawing Line from Point (x1, y1) to (x2, y2)<br />Color : (Optional) sets color of Pixel",
    },
    reset : {
        run : function(args)
        {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            log(1, "Canvas has been cleared");
        },
        syntax : "reset",
        doc : "Clears all the graphics from canvas and redraws the grid",
    },
    drawRect : {
        run : function(args)
        {
            if( args.length < 4 )
            {
                log(0, "Invalid Parameters 4 Parameters are Required Only " + args.length + " provided");
            }
            else
            {
                var x1 = args[0],
                    y1 = args[1],
                    w = args[2],
                    h = args[3],
                    c = args.length > 4 ? args[4] : "#000";
                
                ctx.beginPath();
                ctx.strokeRect(x1, y1, w, h);
                ctx.closePath();
                log(1, "Rectangle was Drawn with Following Parameters<br /><ul><li>x : " + x1 + "</li><li>y : " + y1 + "</li><li>width : " + w + "</li><li>height : " + h + "</li></ul>");
            }
        },
        syntax : "drawRect x1 y1 w h color",
        doc : "Creates a Rectangle starting from x1, y1 and<br />Width = w; Height = h<br />color : (Optional) in HEX<br />Rectangle with Only Borders and No Fill Color",
    },
    strokeText : {
        run : function(args){
            if( args.length < 1 )
            {
                log(0, "Invalid Parameters Atleast 1 Parameter i required");
            }
            else
            {
                var s = args[0],
                    x = args.length > 1 ? parseInt(args[1]) : 10,
                    y = args.length > 2 ? parseInt(args[2]) : 10,
                    h = args.length > 3 ? args[3]+"px " : "12px ",
                    f = args.length > 4 ? h + args[4] : h + "Times",
                    c = args.length > 5 ? args[5] : "#000";
                
                var str = s.split("_");
                s = "";
                for( var i = 0; i < str.length-1; i++)
                {
                    s += str[i] + " ";
                }
                s += str[str.length-1];

                ctx.strokeStyle = c;
                ctx.font = f;
                ctx.beginPath();
                ctx.strokeText(s, x, y);
                ctx.closePath();
                log(1, "Painted " + s + " on Canvas");
            }
        },
        syntax : "strokeText text x y size font color",
        doc : "Paints Text on Canvas<br /><ul><li>text : String that is to be Painted use _ instead of Space</li><li>x : Coordinate</li><li>y : Coordinate</li><li>size : Font Size</li><li>font : Font of String</li><li>color : (Optional) Defines line Color</li></ul>"
    }
    
};

var commands = Object.keys(algo).sort();
var command_buffer = [];
var currCommand = "";
var comCounter = 0;
